<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=9" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>dora.c++ API Documentation</title>
        <link href="tabs.css" rel="stylesheet" type="text/css" />
        <link href="doxygen.css" rel="stylesheet" type="text/css" />
        <link href="navtree.css" rel="stylesheet" type="text/css" />
        <link href="search/search.css" rel="stylesheet" type="text/css" />
        <style>
            body {
                font-family: Arial, sans-serif;
                line-height: 1.6;
                margin: 20px;
            }
            .header {
                background-color: #f8f8f8;
                padding: 20px;
                border-bottom: 1px solid #ddd;
            }
            .header .title {
                font-size: 24px;
            }
            .contents {
                margin-top: 20px;
            }
            .textblock {
                margin-bottom: 40px;
            }
            .textblock h2 {
                border-bottom: 2px solid #ddd;
                padding-bottom: 10px;
                margin-bottom: 20px;
            }
            .textblock h3 {
                margin-top: 20px;
            }
            dl {
                margin-top: 10px;
            }
            dt {
                font-weight: bold;
                margin-top: 10px;
            }
            dd {
                margin-left: 20px;
                margin-bottom: 10px;
            }
            pre {
                background-color: #f0f0f0;
                padding: 10px;
                border: 1px solid #ddd;
                border-radius: 4px;
                overflow-x: auto;
            }
            code {
                font-family: monospace;
            }
            .code-block {
                margin-top: 10px;
                margin-bottom: 10px;
            }
            #side-nav {
                padding-left: 10px;
            }
            #MSearchBox {
                display: none;
            }
        </style>
        <script type="text/javascript" src="jquery.js"></script>
        <script type="text/javascript" src="dynsections.js"></script>
        <script type="text/javascript" src="resize.js"></script>
        <script type="text/javascript" src="navtreedata.js"></script>
        <script type="text/javascript" src="navtree.js"></script>
        <script type="text/javascript" src="search/search.js"></script>
        <script type="text/javascript" src="search/searchdata.js"></script>
    </head>
    <body>
        <div id="top">
            <!-- do not remove this div, it is closed by doxygen! -->
            <div id="titlearea">
                <table cellspacing="0" cellpadding="0">
                    <tbody>
                        <tr style="height: 56px">
                            <td id="projectalign" style="padding-left: 0.5em">
                                <div id="projectname">
                                    API Documentation &#160;<span
                                        id="projectnumber"
                                    ></span>
                                </div>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <!-- end header part -->
            <!-- Generated by Doxygen 1.9.1 -->
            <script type="text/javascript">
                var searchBox = new SearchBox(
                    "searchBox",
                    "search",
                    false,
                    "Search",
                    ".html",
                );
            </script>
            <script type="text/javascript" src="menudata.js"></script>
            <script type="text/javascript" src="menu.js"></script>
            <script type="text/javascript">
                $(function () {
                    initMenu("", true, false, "search.php", "Search");
                    $(document).ready(function () {
                        init_search();
                    });
                });
            </script>
            <div id="main-nav"></div>
        </div>
        <!-- top -->
        <div id="side-nav" class="ui-resizable side-nav-resizable">
            <div id="nav-tree">
                <div id="nav-tree-contents">
                    <div id="nav-sync" class="sync"></div>
                    <ul>
                        <li><a href="#init_dora_node">Init Dora Node</a></li>
                        <li>
                            <a href="#receiving_events">Receiving Events</a>
                        </li>
                        <li><a href="#sending_outputs">Sending Outputs</a></li>
                        <li><a href="#using_arrow_i/o">Using Arrow for I/O</a></li>
                        <li>
                            <a href="#using_the_ros2_bridge"
                                >Using the ROS2 Bridge</a
                            >
                        </li>
                        <li>
                            <a href="#initializing_the_ros2_context"
                                >Initializing the ROS2 Context</a
                            >
                        </li>
                        <li><a href="#creating_nodes">Creating Nodes</a></li>
                        <li><a href="#creating_topics">Creating Topics</a></li>
                        <li><a href="#publish">Publish</a></li>
                        <li><a href="#subscriptions">Subscriptions</a></li>
                        <li>
                            <a href="#combined_event_streams"
                                >Combined Event Streams</a
                            >
                        </li>
                        <li>
                            <a
                                href="#receiving_messages_from_combined_event_stream"
                                >Receiving Messages from Combined Event
                                Stream</a
                            >
                        </li>
                        <li><a href="#constants">Constants</a></li>
                        <li><a href="#service_clients">Service Clients</a></li>
                        <li>
                            <a href="#waiting_for_the_service"
                                >Waiting for the Service</a
                            >
                        </li>
                        <li>
                            <a href="#sending_requests">Sending Requests</a>
                        </li>
                        <li>
                            <a href="#receiving_responses"
                                >Receiving Responses</a
                            >
                        </li>
                    </ul>
                </div>
            </div>
            <div
                id="splitbar"
                style="-moz-user-select: no ne"
                class="ui-resizable-handle"
            ></div>
        </div>
        <script type="text/javascript">
            $(document).ready(function () {
                initNavTree("index.html", "");
                initResizable();
            });
        </script>
        <div id="doc-content">
            <!-- window showing the filter options -->
            <div
                id="MSearchSelectWindow"
                onmouseover="return searchBox.OnSearchSelectShow()"
                onmouseout="return searchBox.OnSearchSelectHide()"
                onkeydown="return searchBox.OnSearchSelectKey(event)"
            ></div>

            <!-- iframe showing the search results (closed by default) -->
            <div id="MSearchResultsWindow">
                <iframe
                    src="javascript:void(0)"
                    frameborder="0"
                    name="MSearchResults"
                    id="MSearchResults"
                >
                </iframe>
            </div>

            <div class="contents">
                <dl class="warning">
                    This documentation is experimental and is not yet linked
                    with the source code. Be aware of any error within this
                    documentation. For more:
                    https://github.com/dora-rs/dora/pull/611
                </dl>

                <h1>Interface Documentation</h1>
                <div class="textblock">
                    <h2>dora-node-api.h</h2>
                    <div class="textblock">
                        <h3>Functions</h3>
                        <dl>
                            <dt><a id="init_dora_node"></a>Init Dora Node</dt>
                            <dd>
                                All nodes need to register themselves with Dora
                                at startup. To do that, call the
                                <code>init_dora_node()</code> function. The
                                function returns a
                                <code>DoraNode</code> instance, which gives
                                access to dora events and enables sending Dora
                                outputs.
                            </dd>
                            <div class="code-block">
                                <pre><code class="language-cpp">
auto dora_node = init_dora_node();
</code></pre>
                            </div>

                            <dt>
                                <a id="receiving_events"></a>Receiving Events
                            </dt>
                            <dd>
                                The <code>dora_node.events</code> field is a
                                stream of incoming events. To wait for the next
                                incoming event, call
                                <code>dora_node.events->next()</code>:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto event = dora_node.events->next();
    </code></pre>
                                </div>
                                The <code>next</code> function returns an opaque
                                <code>DoraEvent</code> type, which cannot be
                                inspected from C++ directly. Instead, use the
                                following functions to read and destructure the
                                event:
                            </dd>
                            <dd>
                                <ul>
                                    <li>
                                        <code>event_type(event)</code> returns a
                                        <code>DoraEventType</code>, which
                                        describes the kind of event. For
                                        example, an event could be an input or a
                                        stop instruction.
                                    </li>
                                    <li>
                                        When receiving a
                                        <code
                                            >DoraEventType::AllInputsClosed</code
                                        >, the node should exit and not call
                                        <code>next</code> anymore.
                                    </li>
                                    <li>
                                        Events of type
                                        <code>DoraEventType::Input</code> can be
                                        downcasted using
                                        <code>event_as_input</code>:
                                        <div class="code-block">
                                            <pre><code class="language-cpp">
auto input = event_as_input(std::move(event));
            </code></pre>
                                        </div>
                                        The function returns a
                                        <code>DoraInput</code> instance, which
                                        has an <code>id</code> and
                                        <code>data</code> field.
                                    </li>
                                    <li>
                                        The input <code>id</code> can be
                                        converted to a C++ string through
                                        <code>std::string(input.id)</code>.
                                    </li>
                                    <li>
                                        The data of inputs is currently of type
                                        <code>rust::Vec&lt;uint8_t&gt;</code>.
                                        Use the provided methods for reading or
                                        converting the data.
                                    </li>
                                    <li>
                                        Note: For sending more datatypes, use Arrow api functions as described in <a href="#using_arrow_i/o">Arrow section</a>.
                                    </li>
                                </ul>
                            </dd>

                            <dt><a id="sending_outputs"></a>Sending Outputs</dt>
                            <dd>
                                Nodes can send outputs using the
                                <code>send_output</code> function and the
                                <code>dora_node.send_output</code> field. Note
                                that all outputs need to be listed in the
                                dataflow YAML declaration file, otherwise an
                                error will occur.
                            </dd>
                            <dd>
                                Example:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
// the data you want to send (NOTE: only byte vectors are supported right now)
std::vector&lt;uint8_t&gt; out_vec{42};
// create a Rust slice from the output vector
rust::Slice&lt;const uint8_t&gt; out_slice{out_vec.data(), out_vec.size()};
// send the slice as output
auto result = send_output(dora_node.send_output, "output_id", out_slice);

// check for errors
auto error = std::string(result.error);
if (!error.empty())
{
    std::cerr << "Error: " << error << std::endl;
    return -1;
}
    </code></pre>
                                </div>
                            </dd>


                            <dt>
                                <a id="using_arrow_i/o"></a>Using Arrow for I/O
                            </dt>
                            <dd>
                                <p>To use Arrow with Dora, you'll need to include the Arrow headers:</p>
                                <pre><code class="language-cpp">
#include &lt;arrow/api.h&gt;
#include &lt;arrow/c/bridge.h&gt;
                            </code></pre>
                            </dd>
                            
                            <dd>
                                <h4>Receiving Arrow Data</h4>
                                <p>After receiving events of type DoraEventType::Input, we can downcast using <code>event_as_arrow_input</code>. We need to pass two pointers to receive results in them which can be imported using the Arrow C Data Interface.</p>
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto event = dora_node.events->next();
auto type = event_type(event);
if(type == DoraEventType::Input)
{
    struct ArrowArray c_array;
    struct ArrowSchema c_schema;

    auto result = event_as_arrow_input(
    std::move(event),
    reinterpret_cast<uint8_t*>(&c_array),
    reinterpret_cast<uint8_t*>(&c_schema)
    );

    if (!result.error.empty()) {
        std::cerr << "Error getting Arrow array: " << result.error << std::endl;
        return -1;
    }

    auto result2 = arrow::ImportArray(&c_array, &c_schema);
    if (!result2.ok()) {
        std::cerr << "Error importing Arrow array: " << result2.status().ToString() << std::endl;
        return -1;
    }
    std::shared_ptr<arrow::Array> input_array = result2.ValueOrDie();

    // Now you can use input_array with Arrow's API
}
                            </code></pre>
                                </div>
                            </dd>
                            
                            <dd>
                                <h4>Sending Arrow Data</h4>
                                <p>Nodes can send outputs using <code>send_arrow_output</code>. To do this, the data must first be converted to the Arrow format and then sent using the provided function. This uses the Arrow C Data interface and supports all types from the <a href="https://arrow.apache.org/docs/format/CDataInterface.html">Arrow C Data Interface</a>.</p>
                                <div class="code-block">
                                    <pre><code class="language-cpp">
// Create an Arrow array
std::shared_ptr<arrow::Array> output_array;

arrow::Int32Builder builder;
builder.Append(10);
builder.Append(100);
builder.Append(1000);
builder.Finish(&output_array);

// Export it to C Data Interface
struct ArrowArray out_c_array;
struct ArrowSchema out_c_schema;

arrow::ExportArray(*output_array, &out_c_array, &out_c_schema);

// Send it as output
auto send_result = send_arrow_output(
    dora_node.send_output,
    "counter",
    reinterpret_cast<uint8_t*>(&out_c_array),
    reinterpret_cast<uint8_t*>(&out_c_schema)
);

// Check for errors
auto error = std::string(send_result.error);
if (!error.empty())
{
    std::cerr << "Error sending Arrow output: " << error << std::endl;
    return -1;
}
                            </code></pre>
                                </div>
                            </dd>
                            
                            <dd>
                                <p>For a complete working example using Arrow with Dora, see the <a href="https://github.com/dora-rs/dora/tree/main/examples/c%2B%2B-arrow-dataflow">C++ Arrow dataflow example</a> in the Dora repository.</p>
                            </dd>
                            <dt>
                                <a id="using_the_ros2_bridge"></a>Using the ROS2
                                Bridge
                            </dt>
                            <dd>
                                The <code>dora-ros2-bindings.h</code> contains
                                function and struct definitions that allow
                                interacting with ROS2 nodes. Currently, the
                                bridge supports publishing and subscribing to
                                ROS2 topics. In the future, we plan to support
                                ROS2 services and ROS2 actions as well.
                            </dd>

                            <dt>
                                <a id="initializing_the_ros2_context"></a
                                >Initializing the ROS2 Context
                            </dt>
                            <dd>
                                The first step is to initialize a ROS2 context:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto ros2_context = init_ros2_context();
    </code></pre>
                                </div>
                            </dd>
                            <dt>
                                <a id="using_the_ros2_bridge"></a>Using the ROS2
                                Bridge
                            </dt>
                            <dd>
                                The <code>dora-ros2-bindings.h</code> contains
                                function and struct definitions that allow
                                interacting with ROS2 nodes. Currently, the
                                bridge supports publishing and subscribing to
                                ROS2 topics. In the future, we plan to support
                                ROS2 services and ROS2 actions as well.
                            </dd>

                            <dt>
                                <a id="initializing_the_ros2_context"></a
                                >Initializing the ROS2 Context
                            </dt>
                            <dd>
                                The first step is to initialize a ROS2 context:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto ros2_context = init_ros2_context();
    </code></pre>
                                </div>
                            </dd>

                            <dt><a id="creating_nodes"></a>Creating Nodes</dt>
                            <dd>
                                After initializing a ROS2 context, you can use
                                it to create ROS2 nodes:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto node = ros2_context->new_node("/ros2_demo", "turtle_teleop");
    </code></pre>
                                </div>
                                The first argument is the namespace of the node
                                and the second argument is its name.
                            </dd>

                            <dt><a id="creating_topics"></a>Creating Topics</dt>
                            <dd>
                                After creating a node, you can use one of the
                                <code>create_topic_&lt;TYPE&gt;</code> functions
                                to create a topic on it. The
                                <code>&lt;TYPE&gt;</code> describes the message
                                type that will be sent on the topic. The Dora
                                ROS2 bridge automatically creates
                                <code>create_topic_&lt;TYPE&gt;</code> functions
                                for all message types found in the sourced ROS2
                                environment.
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto vel_topic = node->create_topic_geometry_msgs_Twist("/turtle1", "cmd_vel", qos_default());
    </code></pre>
                                </div>
                                The first argument is the namespace of the topic
                                and the second argument is its name. The third
                                argument is the QoS (quality of service) setting
                                for the topic. It can be adjusted as desired,
                                for example:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto qos = qos_default();
qos.durability = Ros2Durability::Volatile;
qos.liveliness = Ros2Liveliness::Automatic;
auto vel_topic = node->create_topic_geometry_msgs_Twist("/turtle1", "cmd_vel", qos);
    </code></pre>
                                </div>
                            </dd>

                            <dt><a id="publish"></a>Publish</dt>
                            <dd>
                                After creating a topic, it is possible to
                                publish messages on it. First, create a
                                publisher:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto vel_publisher = node->create_publisher(vel_topic, qos);
    </code></pre>
                                </div>
                                The returned publisher is typed by the chosen
                                topic. It will only accept messages of the
                                topic's type, otherwise a compile error will
                                occur. After creating a publisher, you can use
                                the
                                <code>publish</code> function to publish one or
                                more messages. For example:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
geometry_msgs::Twist twist = {
    .linear = {.x = 1, .y = 0, .z = 0},
    .angular = {.x = 0, .y = 0, .z = 0.5}
};
vel_publisher->publish(twist);
    </code></pre>
                                </div>
                                The <code>geometry_msgs::Twist</code> struct is
                                automatically generated from the sourced ROS2
                                environment. Since the publisher is typed, its
                                <code>publish</code> method only accepts
                                <code>geometry_msgs::Twist</code> messages.
                            </dd>

                            <dt><a id="subscriptions"></a>Subscriptions</dt>
                            <dd>
                                Subscribing to a topic is possible through the
                                <code>create_subscription</code> function on
                                nodes:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto pose_topic = node->create_topic_turtlesim_Pose("/turtle1", "pose", qos_default());
auto pose_subscription = node->create_subscription(pose_topic, qos_default(), event_stream);
    </code></pre>
                                </div>
                                The topic is the topic you want to subscribe to,
                                created using a
                                <code>create_topic_&lt;TYPE&gt;</code> function.
                                The second argument is the quality of service
                                setting, which can be customized as described
                                above. The third parameter is the event stream
                                that the received messages should be merged
                                into. Multiple subscriptions can be merged into
                                the same event stream.
                            </dd>

                            <dt>
                                <a id="combined_event_streams"></a>Combined
                                Event Streams
                            </dt>
                            <dd>
                                Combined event streams enable the merging of
                                multiple event streams into one. The combined
                                stream will then deliver messages from all
                                sources, in order of arrival. You can create
                                such an event stream from Dora's event stream
                                using the
                                <code>dora_events_into_combined</code> function:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto event_stream = dora_events_into_combined(std::move(dora_node.events));
    </code></pre>
                                </div>
                                Alternatively, if you don't want to use Dora,
                                you can also create an empty event stream:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto event_stream = empty_combined_events();
    </code></pre>
                                </div>
                                Note: You should only use
                                <code>empty_combined_events</code> if you're
                                running your executable independent of Dora.
                                Ignoring the events from the
                                <code>dora_node.events</code> channel can result
                                in unintended behavior.
                            </dd>

                            <dt>
                                <a
                                    id="receiving_messages_from_combined_event_stream"
                                ></a
                                >Receiving Messages from Combined Event Stream
                            </dt>
                            <dd>
                                The merged event stream will receive all
                                incoming events of the node, including Dora
                                events and ROS2 messages. To wait for the next
                                incoming event, use its
                                <code>next</code> method:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto event = event_stream.next();
    </code></pre>
                                </div>
                                This returns an event instance of type
                                <code>CombinedEvent</code>, which can be
                                downcasted to Dora events or ROS2 messages. To
                                handle an event, you should check its type and
                                then downcast it:
                                <ul>
                                    <li>
                                        To check for a Dora event, you can use
                                        the
                                        <code>is_dora()</code> function. If it
                                        returns true, you can downcast the
                                        combined event to a Dora event using the
                                        <code>downcast_dora</code> function.
                                    </li>
                                    <li>
                                        ROS2 subscriptions support a
                                        <code>matches</code> function to check
                                        whether a combined event is an instance
                                        of the respective ROS2 subscription. If
                                        it returns true, you can downcast the
                                        event to the respective ROS2 message
                                        struct using the subscription's
                                        <code>downcast</code> function.
                                    </li>
                                </ul>
                                Example:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
if (event.is_dora())
{
    auto dora_event = downcast_dora(std::move(event));
    // handle dora_event as described above
    auto ty = event_type(dora_event);
    if (ty == DoraEventType::Input)
    {
        auto input = event_as_input(std::move(dora_event));
        // etc
    }
    // .. else if
}
else if (pose_subscription->matches(event))
{
    auto pose = pose_subscription->downcast(std::move(event));
    std::cout << "Received pose x:" << pose.x << ", y:" << pose.y << std::endl;
}
else
{
    std::cout << "received unexpected event" << std::endl;
}
    </code></pre>
                                </div>
                            </dd>

                            <dt><a id="constants"></a>Constants</dt>
                            <dd>
                                Some ROS2 message definitions define constants,
                                e.g., to specify the values of an enum-like
                                integer field. The Dora ROS2 bridge exposes
                                these constants in the generated bindings as
                                functions. For example, the
                                <code>STATUS_NO_FIX</code> constant of the
                                <code>NavSatStatus</code> message can be
                                accessed as follows:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
assert((sensor_msgs::const_NavSatStatus_STATUS_NO_FIX() == -1));
    </code></pre>
                                </div>
                                (Note: Exposing them as C++ constants is not
                                possible because it's not supported by cxx yet.)
                            </dd>

                            <dt><a id="service_clients"></a>Service Clients</dt>
                            <dd>
                                To create a service client, use one of the
                                <code>create_client_&lt;TYPE&gt;</code>
                                functions. The
                                <code>&lt;TYPE&gt;</code> describes the service
                                type, which specifies the request and response
                                types. The Dora ROS2 bridge automatically
                                creates
                                <code>create_client_&lt;TYPE&gt;</code>
                                functions for all service types found in the
                                sourced ROS2 environment.
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto add_two_ints = node->create_client_example_interfaces_AddTwoInts(
  "/",
  "add_two_ints",
  qos,
  merged_events
);
    </code></pre>
                                </div>
                                The first argument is the namespace of the
                                service and the second argument is its name. The
                                third argument is the QoS (quality of service)
                                setting for the service. It can be set to
                                <code>qos_default()</code> or adjusted as
                                desired, for example:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
auto qos = qos_default();
qos.reliable = true;
qos.max_blocking_time = 0.1;
qos.keep_last = 1;
    </code></pre>
                                </div>
                                The last argument is the combined event stream
                                that the received service responses should be
                                merged into.
                            </dd>

                            <dt>
                                <a id="waiting_for_the_service"></a>Waiting for
                                the Service
                            </dt>
                            <dd>
                                In order to achieve reliable service
                                communication, it is recommended to wait until
                                the service is available before sending
                                requests. Use the
                                <code>wait_for_service()</code> method for that,
                                e.g.:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
add_two_ints->wait_for_service(node);
    </code></pre>
                                </div>
                                The given node must be the node on which the
                                service was created.
                            </dd>

                            <dt>
                                <a id="sending_requests"></a>Sending Requests
                            </dt>
                            <dd>
                                To send a request, use the
                                <code>send_request</code> method:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
add_two_ints->send_request(request);
    </code></pre>
                                </div>
                                The method sends the request asynchronously
                                without waiting for a response. When the
                                response is received, it is automatically sent
                                to the combined event stream that was given on
                                client creation.
                            </dd>

                            <dt>
                                <a id="receiving_responses"></a>Receiving
                                Responses
                            </dt>
                            <dd>
                                See the "Receiving Messages from Combined Event
                                Stream" section for how to receive events from
                                the combined event stream. To check if a
                                received event is a service response, use the
                                <code>matches</code> method. If it returns true,
                                you can use the <code>downcast</code> method to
                                convert the event to the correct service
                                response type. Example:
                                <div class="code-block">
                                    <pre><code class="language-cpp">
if (add_two_ints->matches(event))
{
    auto response = add_two_ints->downcast(std::move(event));
    std::cout << "Received sum response with value " << response.sum << std::endl;
    ...
}
    </code></pre>
                                </div>
                            </dd>
                        </dl>
                    </div>
                </div>
            </div>
            <!-- contents -->
        </div>
        <!-- doc-content -->
        <!-- start footer part -->
        <div id="nav-path" class="navpath">
            <ul>
                <li class="footer">
                    Generated by
                    <a href="https://www.doxygen.org/index.html"
                        ><img
                            class="footer"
                            src="doxygen.svg"
                            width="104"
                            height="31"
                            alt="doxygen"
                    /></a>
                    1.9.1
                </li>
            </ul>
        </div>
    </body>
</html>
